package com.springmvc.context;

import com.springmvc.anotation.AutoWired;
import com.springmvc.anotation.Controller;
import com.springmvc.anotation.Service;
import com.springmvc.exception.ContextException;
import com.springmvc.xml.XmlParser;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;

public class WebApplicationContext {
    private final String contextConfigLocation;
    private final List<String> classNameList = new ArrayList<String>();

    public Map<String, Object> getBeanMap() {
        return beanMap;
    }

    private final Map<String, Object> beanMap = new HashMap<>();

    public WebApplicationContext(String contextConfigLocation) {
        this.contextConfigLocation = contextConfigLocation;
        System.out.print(this.contextConfigLocation);
        System.out.println("Tomcat 启动。。。");
    }

    public void refresh() {
        // springmvc.xml
        String basePackage = XmlParser.getBasePackage(contextConfigLocation.split(":")[1]);
        String[] basePackages = basePackage.split(",");
        for (String aPackage : basePackages) {
            // com.xl
            scanPackage(aPackage);
        }
        System.out.println("所有类：" + classNameList);
        // 实例化bean，并保存
        excuteInstance();
        System.out.println("bean实例：" + beanMap);
        // 自动注入
        excuteAutoWired();
    }



    private void excuteAutoWired() {
        classEmptyCheck();
        beanEmptyCheck();
        try {
            for (Map.Entry<String, Object> stringObjectEntry : beanMap.entrySet()) {
                String key = stringObjectEntry.getKey();
                Object bean = stringObjectEntry.getValue();
                Field[] declaredFields = bean.getClass().getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    AutoWired autoWiredAnotation = declaredField.getAnnotation(AutoWired.class);
                    String beanName = autoWiredAnotation.value();
                    if ("".equals(beanName)) {
                        Class<?> type = declaredField.getType();
                        beanName = StringUtils.uncapitalize(type.getSimpleName());
                    }
                    declaredField.setAccessible(true);
                    declaredField.set(bean, beanMap.get(beanName));
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    private void beanEmptyCheck() {
        if (beanMap.isEmpty()) {
            throw new ContextException("bean 空");
        }
    }

    private void classEmptyCheck() {
        if (classNameList.size() == 0) {
            throw new ContextException("没有扫描到实例化类");
        }
    }

    private void excuteInstance() {
        classEmptyCheck();
        try {
            for (String aClassName : classNameList) {
                Class<?> clazz = Class.forName(aClassName);
                // UserController -> userController
                if (clazz.isAnnotationPresent(Controller.class)) {
                    String beanName = StringUtils.uncapitalize(clazz.getSimpleName());
                    // 映射bean  userController->controller实例
                    beanMap.put(beanName, clazz.getDeclaredConstructor().newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    Service annotation = clazz.getAnnotation(Service.class);
                    String beanName = annotation.value();
                    // 注解没赋值，按接口或类名映射
                    if ("".equals(beanName)) {
                        Class<?>[] interfaces = clazz.getInterfaces();
                        // 有接口按接口名映射
                        if (interfaces.length > 0) {
                            Class<?> anInterface = interfaces[0];
                            beanName = StringUtils.uncapitalize(anInterface.getSimpleName());
                        } else {
                            // 无接口按类名映射
                            beanName = StringUtils.uncapitalize(clazz.getSimpleName());
                        }
//                        for (Class<?> anInterface : interfaces) {
//                            beanName = anInterface.getSimpleName().substring(0, 1).toLowerCase(Locale.ROOT)
//                                    + anInterface.getSimpleName().substring(1);
//                            beanMap.put(beanName, anInterface.getDeclaredConstructor().newInstance());
//                        }
                    }
                    beanMap.put(beanName, clazz.getDeclaredConstructor().newInstance());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void scanPackage(String aPackage) {
        // 将com.xl转换为/com/xl
        URL resource = this.getClass().getClassLoader().getResource("/" + aPackage.replaceAll("\\.", "/"));
        assert resource != null;
        String path = resource.getFile();
        File dir = new File(path);
        for (File file : Objects.requireNonNull(dir.listFiles())) {
            if(file.isDirectory()) {
                scanPackage(aPackage + "." + file.getName());
            } else {
                classNameList.add(aPackage + "." + file.getName().replaceAll(".class", ""));
            }
        }
    }
}
